using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NLog;

namespace LocalDns.CLI
{
    internal static class Program
    {
        private const string DefaultPipeName = "LocalDnsServicePipe";

        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        private static async Task<int> Main(string[] args)
        {
            // 总执行超时（毫秒），超过该时间仍未完成则退出
            const int overallTimeoutMs = 2_000;
            var completed = false;
            _ = Task.Run(async () =>
            {
                await Task.Delay(overallTimeoutMs);
                if (!completed)
                {
                    _logger.Error($"[CLI] 总执行超时（{overallTimeoutMs}ms），即将退出。");
                     Console.WriteLine("服务未响应，可能已停止或未启动。");
                    Environment.Exit(2);
                }
            });
             // Usage: LDNS <COMMAND LINE>
             // Options:
             //   -n, --name <pipeName>     指定管道名称（默认 LocalDnsServicePipe）
             //   -t, --timeout <ms>        连接超时毫秒（默认 3000）
             //   -r, --retries <count>     连接或执行失败时的重试次数（默认 3）
             //       --retry-delay <ms>    两次重试间的等待毫秒（默认 300）
             if (args == null || args.Length == 0)
             {
                 PrintUsage();
                 completed = true;
                 return 1;
             }

            string pipeName = DefaultPipeName;
            int timeoutMs = 3000;
            int retries = 3;
            int retryDelayMs = 300;
            var cmdBuilder = new StringBuilder();

            for (int i = 0; i < args.Length; i++)
            {
                var a = args[i];
                if (string.Equals(a, "-n", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--name", StringComparison.OrdinalIgnoreCase))
                {
                    if (i + 1 < args.Length)
                    {
                        pipeName = args[i + 1];
                        i++;
                        continue;
                    }
                }
                else if (string.Equals(a, "-t", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--timeout", StringComparison.OrdinalIgnoreCase))
                {
                    if (i + 1 < args.Length && int.TryParse(args[i + 1], out var t) && t > 0)
                    {
                        timeoutMs = t;
                        i++;
                        continue;
                    }
                }
                else if (string.Equals(a, "-r", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--retries", StringComparison.OrdinalIgnoreCase))
                {
                    if (i + 1 < args.Length && int.TryParse(args[i + 1], out var r) && r >= 0 && r <= 20)
                    {
                        retries = r;
                        i++;
                        continue;
                    }
                }
                else if (string.Equals(a, "--retry-delay", StringComparison.OrdinalIgnoreCase))
                {
                    if (i + 1 < args.Length && int.TryParse(args[i + 1], out var d) && d >= 0 && d <= 10000)
                    {
                        retryDelayMs = d;
                        i++;
                        continue;
                    }
                }
                else
                {
                    // 作为命令拼接（保留空格）
                    if (cmdBuilder.Length > 0) cmdBuilder.Append(' ');
                    cmdBuilder.Append(a);
                }
            }

            string commandLine = cmdBuilder.ToString();
            if (string.IsNullOrWhiteSpace(commandLine))
            {
                Console.Error.WriteLine("错误：未提供命令。\n");
                PrintUsage();
                completed = true;
                return 1;
             }

            // 特殊处理：服务控制命令采用进程调用而非IPC
            var cmdUpper = commandLine.Trim().ToUpperInvariant();
            if (cmdUpper == "START" || cmdUpper == "STOP" || cmdUpper == "RESTART")
            {
                int rc = await ExecuteServiceControlAsync(cmdUpper);
                completed = true;
                return rc;
            }

            for (int attempt = 1; attempt <= Math.Max(1, retries); attempt++)
            {
                try
                {
                    _logger.Debug($"[CLI] 开始建立连接尝试 {attempt}");
                    using var client = new NamedPipeClientStream(
                        ".",
                        pipeName,
                        PipeDirection.InOut,
                        PipeOptions.Asynchronous);
                    _logger.Debug($"[CLI] 目标管道: \\.\\pipe\\{pipeName} (server=.)");

                    Console.OutputEncoding = Encoding.UTF8;
                    Console.InputEncoding = Encoding.UTF8;
                    Console.CancelKeyPress += (_, e) => { e.Cancel = true; };
                    Console.TreatControlCAsInput = true;
                    // 简化控制台设置，避免无关干扰
                    // 简化控制台设置，避免无关干扰
                     
                     await client.ConnectAsync(timeoutMs);
                    // 移除不受支持的超时设置
                     _logger.Debug("[CLI] 管道连接已建立，进入读写阶段...");
                    _logger.Debug("[CLI] 准备创建 StreamReader...");
                    using var reader = new StreamReader(client, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true);
                    _logger.Debug("[CLI] StreamReader 创建完成。");
                    
                    // 预读取服务端握手行（CONNECTED），最多等待 500ms，避免服务端初次写入阻塞
                    _logger.Debug("[CLI] 等待握手行（最多500ms）...");
                    try {
                        var helloTask = reader.ReadLineAsync();
                        var helloCompleted = await Task.WhenAny(helloTask, Task.Delay(500));
                        if (helloCompleted == helloTask)
                        {
                            var hello = await helloTask;
                            _logger.Debug("[CLI] 握手: " + (hello ?? "<null>"));
                        }
                        else
                        {
                            _logger.Debug("[CLI] 握手读取超时，继续");
                        }
                    } catch { /* 忽略握手读取异常 */ }
                    
                    _logger.Debug("[CLI] 准备创建 StreamWriter...");
                    using var writer = new StreamWriter(client, Encoding.UTF8, bufferSize: 1024, leaveOpen: true) { AutoFlush = true };
                    _logger.Debug("[CLI] StreamWriter 创建完成。");
                    
                    // 发送命令（与UI一致）
                    _logger.Debug("[CLI] 即将发送命令: " + commandLine);
                    await writer.WriteLineAsync(commandLine);
                    await writer.FlushAsync();
                    _logger.Debug("[CLI] 命令已发送，开始读取返回...");
                    
                    // 读取返回直到 __END__
                    var output = new StringBuilder();
                    string? line;
                     while ((line = await reader.ReadLineAsync()) != null)
                     {
                         if (string.Equals(line, "__END__", StringComparison.Ordinal))
                             break;
                         output.AppendLine(line);
                     }
                     _logger.Debug("[CLI] 读取完成，准备输出结果...");

                    string result = output.ToString().TrimEnd();
                    if (!string.IsNullOrWhiteSpace(result))
                    {
                        var firstLine = result.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                        if (firstLine.Length > 0 && firstLine[0].StartsWith("ERROR", StringComparison.OrdinalIgnoreCase))
                        {
                            // 服务端明确错误，不再重试
                            Console.Error.WriteLine(result);
                            return 1;
                        }
                        Console.WriteLine(result);
                        completed = true;
                        return 0;
                    }

                    // 无输出，视为失败，尝试重试
                    if (attempt < Math.Max(1, retries))
                    {
                        await Task.Delay(retryDelayMs);
                        continue;
                    }
                    _logger.Error("命令执行无输出或失败。");
                    completed = true;
                    return 1;
                }
                catch (TimeoutException)
                {
                    if (attempt < Math.Max(1, retries))
                    {
                        await Task.Delay(retryDelayMs);
                        continue;
                    }
                    _logger.Error($"连接超时（{timeoutMs}ms）。请确认服务已运行且管道名正确：{pipeName}");
                    completed = true;
                    return 1;
                }
                catch (OperationCanceledException)
                {
                    if (attempt < Math.Max(1, retries))
                    {
                        await Task.Delay(retryDelayMs);
                        continue;
                    }
                    _logger.Error($"连接超时（{timeoutMs}ms）。请确认服务已运行且管道名正确：{pipeName}");
                    completed = true;
                    return 1;
                }
                catch (Exception ex)
                {
                    if (attempt < Math.Max(1, retries))
                    {
                        await Task.Delay(retryDelayMs);
                        continue;
                    }
                    _logger.Error($"IPC 通信异常：{ex.Message}");
                    completed = true;
                    return 1;
                }
            }
 
            completed = true;
            return 1;
        }

        private static void PrintUsage()
        {
            Console.WriteLine("LocalDns CLI - 通过命名管道操作服务");
            Console.WriteLine("用法: LDNS [-n <pipeName>] [-t <ms>] <COMMAND LINE>");
            Console.WriteLine("示例:");
            Console.WriteLine("  LDNS START");
            Console.WriteLine("  LDNS STOP");
            Console.WriteLine("  LDNS RESTART");
            Console.WriteLine("  LDNS STATUS");
            Console.WriteLine("  LDNS LIST_COMMANDS");
            Console.WriteLine("  LDNS HELP");
            Console.WriteLine("  LDNS \"ADD_RECORD --domain example.com --ip 1.2.3.4\"");
            Console.WriteLine("选项:");
            Console.WriteLine("  -n, --name <pipeName>     指定管道名称（默认 LocalDnsServicePipe）");
            Console.WriteLine("  -t, --timeout <ms>        连接超时毫秒（默认 3000）");
            Console.WriteLine("  -r, --retries <count>     失败时的重试次数（默认 3）");
            Console.WriteLine("      --retry-delay <ms>    重试间隔毫秒（默认 300）");
        }

        // 通过进程执行服务控制命令（START/STOP/RESTART）
        private static async Task<int> ExecuteServiceControlAsync(string command)
        {
            try
            {
                // 优先查找安装目录结构：cli 相邻上一级目录为服务根目录
                string baseDir = AppDomain.CurrentDomain.BaseDirectory;
                string exeCandidate = Path.GetFullPath(Path.Combine(baseDir, "..", "LocalDnsService.exe"));
                string dllCandidate = Path.GetFullPath(Path.Combine(baseDir, "..", "LocalDnsService.dll"));
                string exeFallback = Path.Combine(baseDir, "LocalDnsService.exe");
                string dllFallback = Path.Combine(baseDir, "LocalDnsService.dll");

                string? exePath = null;
                string? dllPath = null;
                if (File.Exists(exeCandidate)) exePath = exeCandidate; else if (File.Exists(exeFallback)) exePath = exeFallback;
                if (File.Exists(dllCandidate)) dllPath = dllCandidate; else if (File.Exists(dllFallback)) dllPath = dllFallback;

                if (command == "START")
                {
                    if (!string.IsNullOrEmpty(exePath))
                    {
                        // 启动服务进程并立即返回
                        var psi = new System.Diagnostics.ProcessStartInfo(exePath)
                        {
                            UseShellExecute = false,
                            CreateNoWindow = true,
                            RedirectStandardOutput = false,
                            RedirectStandardError = false
                        };
                        System.Diagnostics.Process.Start(psi);
                        Console.WriteLine("OK: 服务启动命令已执行（已拉起进程）");
                        return 0;
                    }
                    else if (!string.IsNullOrEmpty(dllPath))
                    {
                        var psi = new System.Diagnostics.ProcessStartInfo("dotnet", $"\"{dllPath}\"")
                        {
                            UseShellExecute = false,
                            CreateNoWindow = true,
                            RedirectStandardOutput = false,
                            RedirectStandardError = false
                        };
                        System.Diagnostics.Process.Start(psi);
                        Console.WriteLine("OK: 服务启动命令已执行（dotnet运行DLL）");
                        return 0;
                    }
                    Console.Error.WriteLine("ERROR: 未找到 LocalDnsService 可执行文件或 DLL");
                    return 1;
                }
                else
                {
                    // STOP/RESTART 通过 --command 进程参数执行并采集输出
                    string args = $"--command {command}";
                    if (!string.IsNullOrEmpty(exePath))
                    {
                        string output = await RunProcessAsync(exePath, args);
                        Console.WriteLine(output);
                        return output.StartsWith("ERROR", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
                    }
                    else if (!string.IsNullOrEmpty(dllPath))
                    {
                        string output = await RunProcessAsync("dotnet", $"\"{dllPath}\" {args}");
                        Console.WriteLine(output);
                        return output.StartsWith("ERROR", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
                    }
                    Console.Error.WriteLine("ERROR: 未找到 LocalDnsService 可执行文件或 DLL");
                    return 1;
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"ERROR: 执行服务控制命令失败: {ex.Message}");
                return 1;
            }
        }

        // 运行外部进程并收集标准输出直到退出
        private static async Task<string> RunProcessAsync(string fileName, string arguments)
        {
            var psi = new System.Diagnostics.ProcessStartInfo(fileName, arguments)
            {
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding = Encoding.UTF8
            };
            using var proc = System.Diagnostics.Process.Start(psi);
            if (proc == null)
            {
                return "ERROR: 无法启动进程";
            }
            var sb = new StringBuilder();
            var tcs = new TaskCompletionSource<bool>();

            proc.OutputDataReceived += (_, e) => { if (e.Data != null) sb.AppendLine(e.Data); };
            proc.ErrorDataReceived += (_, e) => { if (e.Data != null) sb.AppendLine(e.Data); };
            proc.BeginOutputReadLine();
            proc.BeginErrorReadLine();
            await Task.Run(() => proc.WaitForExit());
            return sb.ToString().TrimEnd();
        }
    }
}